package com.guchenbo.example.proxy;

import java.lang.reflect.Proxy;
import java.util.Arrays;

public class ProxyDemo {
    public static void main(String[] args) {
        EchoService service = new EchoServiceImpl();
        System.out.println(service);
        service.echo("msg1");

        EchoInvocationHandler invocationHandler = new EchoInvocationHandler(service);
        for (Class<?> anInterface : EchoService.class.getInterfaces()) {
            System.out.println(anInterface.getName());
        }
        for (Class<?> anInterface : service.getClass().getInterfaces()) {
            System.out.println(anInterface.getName());
        }

        System.out.println(EchoService.class.getInterfaces().length);
        System.out.println(EchoService.class.getClasses().length);

        System.out.println(service.getClass().getInterfaces().length);
        System.out.println(service.getClass().getClasses().length);
        Object proxy = Proxy.newProxyInstance(EchoService.class.getClassLoader(), EchoService.class.getInterfaces(),
                        invocationHandler);
        System.out.println(proxy);
        // false
        System.out.println(proxy instanceof EchoService);
        System.out.println(isProxyOfSameInterfaces(proxy, service.getClass()));

        Object pr = Proxy.newProxyInstance(EchoService.class.getClassLoader(), service.getClass().getInterfaces(),
                        invocationHandler);
        System.out.println(pr);
        // true
        System.out.println(pr instanceof EchoService);
        System.out.println(isProxyOfSameInterfaces(pr, service.getClass()));

        Object pr2 = Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(),
                        invocationHandler);
        System.out.println(pr2);
        // true
        System.out.println(pr2 instanceof EchoService);
    }

    private static boolean isProxyOfSameInterfaces(Object arg, Class<?> proxyClass) {
        return proxyClass.isInstance(arg)
                        // Equal proxy instances should mostly be instance of proxyClass
                        // Under some edge cases (such as the proxy of JDK types serialized and then deserialized)
                        // the proxy type may not be the same.
                        // We first check isProxyClass() so that the common case of comparing with non-proxy objects
                        // is efficient.
                        || (Proxy.isProxyClass(arg.getClass())
                        && Arrays.equals(arg.getClass().getInterfaces(), proxyClass.getInterfaces()));
    }
}
